﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

using NUnitResults;

namespace NUnitResultsExplorer
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        #region Constructor

        /// <summary>
        /// Creates an instance of the main window.
        /// </summary>
        public MainWindow()
        {
            InitializeComponent();

            var cbClose = new CommandBinding(ApplicationCommands.Close);
            cbClose.Executed += new ExecutedRoutedEventHandler(cbClose_Executed);

            var cbOpen = new CommandBinding(ApplicationCommands.Open);
            cbOpen.Executed += new ExecutedRoutedEventHandler(cbOpen_Executed);

            var cbAbout = new CommandBinding(NUnitExplorerCommands.AboutCommand);
            cbAbout.Executed += new ExecutedRoutedEventHandler(cbAbout_Executed);

            var cbExpandAll = new CommandBinding(NUnitExplorerCommands.ExpandAllCommand);
            cbExpandAll.CanExecute += new CanExecuteRoutedEventHandler(cbExpandAll_CanExecute);
            cbExpandAll.Executed += new ExecutedRoutedEventHandler(cbExpandAll_Executed);

            var cbCollapseAll = new CommandBinding(NUnitExplorerCommands.CollapseAllCommand);
            cbCollapseAll.CanExecute += new CanExecuteRoutedEventHandler(cbCollapseAll_CanExecute);
            cbCollapseAll.Executed += new ExecutedRoutedEventHandler(cbCollapseAll_Executed);

            CommandBindings.Add(cbClose);
            CommandBindings.Add(cbOpen);
            CommandBindings.Add(cbAbout);
            CommandBindings.Add(cbExpandAll);
            CommandBindings.Add(cbCollapseAll);
        }

        #endregion

        #region Methods

        /// <summary>
        /// Loads the results from the specified file, and if necessary, shows the
        /// errors and warnings dialog.
        /// </summary>
        /// <param name="filePaths"></param>
        private void LoadResults(IEnumerable<String> filePaths)
        {
            if (filePaths == null)
            {
                throw new ArgumentNullException("filePaths");
            }

            var resultFiles = filePaths.Select(filePath => new ResultFile(new FileStreamProvider(filePath)))
                                       .ToList();

            var results = resultFiles.SelectMany(r => r.ReadTestResults())
                                     .Select(r => FromTestResult(r))
                                     .ToList();

            var warnings = resultFiles.SelectMany(r => r.Warnings)
                                      .ToList();

            DataContext = results;

            if (warnings.Count > 0)
            {
                ShowWarnings(warnings);
            }
        }

        /// <summary>
        /// Shows the errors and warnings dialog.
        /// </summary>
        /// <param name="warnings"></param>
        private void ShowWarnings(List<ResultFile.Warning> warnings)
        {
            var wndWarnings = new WarningsWindow
            {
                DataContext = warnings,
                Owner = this
            };

            wndWarnings.ShowDialog();
        }

        /// <summary>
        /// Creates Expandables from ITestResults.
        /// </summary>
        /// <param name="result"></param>
        /// <returns></returns>
        public static Expandable<ITestResult> FromTestResult(ITestResult result)
        {
            return new Expandable<ITestResult>(
                result, 
                result != null &&
                (result.SuiteType == SuiteType.Assembly ||
                 result.SuiteType == SuiteType.Namespace ||
                 result.SuiteType == SuiteType.TestProject),
                result.InnerCases.Select(r => FromTestResult(r)).ToList());
        }

        #endregion

        #region Command Execution

        /// <summary>
        /// Logic allowing the opening of result files.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void cbOpen_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            using (var ofd = new System.Windows.Forms.OpenFileDialog { DefaultExt = "xml", Filter = "NUnit Result Files (*.xml)|*.xml", Multiselect = true })
            {
                if (ofd.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                {
                    LoadResults(ofd.FileNames);
                }
            }
        }

        /// <summary>
        /// Opens the about window.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void cbAbout_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            var wndAbout = new AboutWindow
            {
                Owner = this
            };
            wndAbout.ShowDialog();
        }

        /// <summary>
        /// Closes the window.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void cbClose_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            Close();
        }

        /// <summary>
        /// Determines whether or not the collapse all command can execute.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void cbCollapseAll_CanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            e.CanExecute =
                (trv.SelectedItem) != null &&
                !((trv.SelectedItem as Expandable<ITestResult>).Object is TestCase);
        }

        /// <summary>
        /// Collapses all of the nodes starting at the selected node.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void cbCollapseAll_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            var result = trv.SelectedItem as Expandable<ITestResult>;

            if (result != null)
            {
                result.SetExpanded(false);
            }
        }

        /// <summary>
        /// Determines whether or not the expand all command can execute.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void cbExpandAll_CanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            e.CanExecute =
                (trv.SelectedItem) != null &&
                !((trv.SelectedItem as Expandable<ITestResult>).Object is TestCase);
        }

        /// <summary>
        /// Expands all nodes starting at the selected node.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void cbExpandAll_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            var result = trv.SelectedItem as Expandable<ITestResult>;

            if (result != null)
            {
                result.SetExpanded(true);
            }
        }

        #endregion

        #region Event Handlers

        /// <summary>
        /// Ensures that right clicking a tree node correctly selects it.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void trv_PreviewMouseRightButtonDown(Object sender, MouseButtonEventArgs e)
        {
            var node = (TreeViewItem)sender;
            node.IsSelected = true;
            node.Focus();
        }

        #endregion
    }
}
